﻿<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
    <head>
		<meta http-equiv="Content-Type" content="application/xhtml+xml; charset=UTF-8" />
        <title>My movies</title>
        <script type="text/javascript" src="jquery-1.6.4.min.js"></script>
        <link rel="stylesheet" type="text/css" href="common.css"/>
    </head>
    <body>
		<div id="modal"></div>
		<div id="header">
			<a id="btunmatched" class="hidden">Unmathched</a>
			-
			<a class="btrefresh">Refresh <span class="refreshtime">0</span>ms</a>
			-
			<select id="sort">
				<option value="date" selected="selected">Date added</option>
				<option value="title">Title</option>
				<option value="rating">IMDB rating</option>
				<option value="duration">Duration</option>
				<option value="year">Year</option>
			</select>
			<input type="checkbox" id="descending" CHECKED/>
			<label for="descending">descending</label>
			-
			<select id="tagfilter"></select>
		</div>
		<div id="movieswrapper">
			<div id="movies"></div>
		</div>
		<img id="load" src="load.gif"/>
		
		<div id="templates">
			<ul class="tageditor">
				<li>
					<div class="add">
						<input type="text" class="addnew"/>
					</div>
				</li>
			</ul>
			<div class="movieclassic movieroot">
				<img class="cover" />
				<div class="content">
					<h2></h2>
					<p class="tags"></p>
                    <p class="genres"></p>
					<p class="directors"></p>
                    <p class="principals"></p>
					<p class="plot"></p>
					<p class="actions">
						<a class="star" target="_blank"></a>
						<a class="allocine" target="_blank">Allociné</a>
						<a class="play">Play</a>
						<a class="edittags">Tags</a>
						<a class="showfiles"></a>
						<a class="delmatch">Del match</a>
					</p>
					<p class="files hidden"></p>
				</div>
				<div class="clear"></div>
			</div>
			<div class="matcher">
				<div class="content">
					<a class="file"></a>
					<br/>
					<input type="text" name="q"/>
					-
					<a class="btignore">Add to ignore list</a>
					-
					<a class="btskip">Skip</a>
				</div>
				<div class="results"></div>
			</div>
			<div class="result">
				<a class="btok"></a>
				<b class="title"></b><br/>
				<span class="infos"></span>
			</div>
		</div>
        <script type="text/javascript">
            $(function () {
				if(navigator.appVersion.indexOf("wOSBrowser")>-1){
					var t, header = $('#header');
					$(window).scroll(function(){
						if(t)
							clearTimeout(t);
						else
							header.hide();
						t = setTimeout(function(){
							header.fadeIn(800);
							t = null;
						}, 500);
					});
				}
			
				$.fn.m = function(){
					var e = this;
					while(e.length){
						var d = e.data('m');
						if(d)return d;
						e = e.parent();
					}
				};
				
				var _data;
				var _jMovies = $('#movies');
				var _jModal = $('#modal');
				var _btUnmatched = $('#btunmatched');
				var _jTemplates = $('#templates');
				//Usefull to test/edit layout
				var _baseUrl = window.location.href.indexOf('file://') === 0
					? 'http://localhost:8080' : '';
				var _jSort = $('#sort');
				var _jTagFilter = $('#tagfilter');
				var _jDescending = $('#descending');
				var _allTags = {};
					
				var _srv = {
					call:function(action, params, cb){
						return $.getJSON(_baseUrl + '/*' + action + '?jsonp=?', params, cb);
					},
					play:function(f){
						return this.call('play', { f: f });
					},
					getData:function(cb){
						return this.call('movies', cb);
					},
					searchImdb:function(f, q, cb){
						return this.call('searchImdb', { f: f, q:q }, cb);
					},
					setMatch: function(f, id){
						return this.call('setMatch', {f:f || '', id:id || ''}, function(o){
							setData(o);
						});
					},
					setTag: function(tag, id, del){
						return this.call('setTag', {tag:tag || '', id:id || '', del: del ? 1 : 0}, function(o){
							setData(o);
						});
					}
				};
					
				function showModal(v){
					_jModal.empty().append(v);
					if(!_jModal.is(':visible'))
						_jModal.slideDown(200);
				}
				
				function hideModal(){
					if(_jModal.is(':visible'))
						_jModal.slideUp(200);
				}
				
				function match(files, index){
					index = index || 0;
					if(files.length <= index){
						hideModal();
						return;
					}
					var f = files[index];
					var v = getTemplate('matcher');
					$('.btskip', v).click(function(){
						match(files, index+1);
					});
					
					$('.btignore', v).click(function(){
						//todo: add to ignore list
						match(files, index+1);
					});
					var xhr;
					var field = $('[name=q]', v);
					var search = function(f, q){
						if(xhr)
							xhr.abort();
						xhr = _srv.searchImdb(f, q, function(o){
							xhr = null;
							if(!field.val())
								field.val(o.Q);
							var div = $('.results', v).empty();
							var t = getTemplate('result');
							if(!o.Results.length)
								div.append($('<div/>').addClass('noresult').text('No result'));
							$.each(o.Results, function(k, r){
								var e = t.clone();
								$('.title', e).text(r.Title);
								$('.infos', e).text(r.Infos);
								e.click(function(){
									_srv.setMatch(f, r.ImdbId);
									match(files, index+1);
								});
								div.append(e);
							});
						});
					};
					
					$('.file', v).text(f).click(function(){_srv.play(f);});
					field.keypress(function(e){
						if((e.keyCode || e.which) != 13)
							return;
						search(f, field.val());
					});
					
					search(f);
					showModal(v);
				}
				
				function getTemplate(c){
					return $('.' + c, _jTemplates).clone();
				}
				
				var movieclassicTemplate = getTemplate('movieclassic');
				function makeMovieClassic(m){
					var e = movieclassicTemplate.clone().data('m', m);
					$('.cover', e).attr('src', _baseUrl + '/*cover/300x/' + (m.Cover || ''));
					$('h2', e).text(m.Title + (m.Year ? ' - ' + m.Year : ''));
					$('.genres', e).text(Math.round(m.Duration/60) + ' min - ' + m.Genres.join(' - '));
					$('.tags', e).text('Tags: ' + m.Tags.join(' - ')).toggle(!!m.Tags.length);
					$('.directors', e).text('By: ' + m.Directors.join(' - ')).toggle(!!m.Directors.length);
					$('.principals', e).text('With: ' + m.Principals.join(' - ')).toggle(!!m.Principals.length);
					$('.plot', e).text(m.Plot);
					$('.allocine', e).attr('href', 'http://www.google.fr/search?' + $.param({hl:'fr', btnI:'J\'ai de la chance', q:
						'site:allocine.fr/film ' + m.Title}));
					$('.star', e).text((m.ImdbRating || 'No rating')+ ' on IMDB').attr('href', 'http://imdb.com/title/' + m.ImdbId);
					$('.showfiles', e).text(m.Files.length + ' file' + (m.Files.length > 1 ? 's':''));
					return e;
				}
				
				function fullUpdateMovies(ms){
					console.debug('fullUpdateMovies');
					var actuals = {};
					_jMovies.detach();
					
					_jMovies.children().each(function(){
						var e = $(this);
						var m = e.data('m');
						actuals[m.Hash] = e;
					}).detach();

					var tag = _jTagFilter.val();
					for(var i in ms){
						var m = ms[i];
						if(tag && $.inArray(tag, m.Tags) < 0)
							continue;
						var e = actuals[m.Hash] || makeMovieClassic(m);
						_jMovies.append(e);
					}
					$('#movieswrapper').append(_jMovies);
				}
				
				function updateMovies(ms){
					var actuals = {};
					
					var actuals = _jMovies.children();
					for(var i=0; i < ms.length; i++){
						var m = ms[i];
						var e = actuals.eq(i);
						var a = e.data('m');
						
						//Append
						if(!a){
							//To mutch elements to append, full refresh will be faster
							if(ms.length - i > 10){
								fullUpdateMovies(ms);
								return;
							}
							
							makeMovieClassic(m).appendTo(_jMovies);
							continue;
						}
						
						//No change
						if(a.Hash == m.Hash){
							continue;
						}
						
						//Delete
						var next = actuals.eq(i+1).data('m');
						if(next && next.Hash == m.Hash){
							e.remove();
							continue;
						}
						//Insert
						if(ms.length > i+1 && a.Hash == ms[i+1].Hash){
							makeMovieClassic(m).insertBefore(e);
							continue;
						}
						//Update
						if(!next ||(ms.length > i && next.Hash == ms[i+1].Hash)){
							e.replaceWith(makeMovieClassic(m));
							continue;
						}
						//To much changes, do a full refresh
						fullUpdateMovies(ms);
						return;
					}
				}
				
				function setData(data){
					_data = data;
					
					//Calculate tags
					_allTags = {};
					for(var i in data.Movies){
						var m = data.Movies[i];
						for(var j in m.Tags){
							var t = m.Tags[j];
							_allTags[t] = (_allTags[t] + 1) || 1;
						}
					};
					
					//Update tag filter
					var filterVal = _jTagFilter.val();
					_jTagFilter.empty();
					$('<option/>')
						.text('Filter by tag...')
						.attr('value', '')
						.appendTo(_jTagFilter);
					$.each(_allTags, function(t, n){
						$('<option/>')
							.text(t + ' (' + n + ')')
							.attr('value', t)
							.appendTo(_jTagFilter);
					});
					_jTagFilter.val(filterVal);
					
					console.debug(_allTags);
					refresh();
				}
				
				function refresh(){
					var d1 = $.now();
					
					var sort = _jSort.val();
					var direction = _jDescending.is(':checked') ? -1 : 1;
					
					var movies = _data.Movies.sort(function(a, b){
						switch(sort){
							case 'title': return (a.Title.localeCompare(b.Title)) * direction;
							case 'rating': return (a.ImdbRating - b.ImdbRating) * direction;
							case 'duration': return (a.Duration - b.Duration) * direction;
							case 'year': return (a.Year - b.Year) * direction;
							default: return (a.TimeAdded - b.TimeAdded) * direction;
						}
					});
					
					updateMovies(movies);
					_btUnmatched
						.text(_data.Unmatched.length + ' unmatched')
						.toggle(_data.Unmatched.length ? true : false).unbind().click(function(){
							match(_data.Unmatched);
						});
					$('.refreshtime').text($.now() - d1);
				};
				
				//live events
				$('.showfiles', _jMovies).live('click', function () {
				    var e = $(this);
				    var div = $('.files', e.closest('.content'));
				    var files = e.m().Files;
				    if (div.is(':empty')) {
				        $.each(files, function (i, v) {
				            $('<a/>').addClass('file').text(v).click(function () {
				                _srv.play(v);
				            }).appendTo(div);
				        });
				    }
				    div.slideToggle(Math.min(500, files.length * 20));
				});

				$('.delmatch', _jMovies).live('click', function () {
					var e = $(this);
				    _srv.setMatch(null, e.m().ImdbId);
					e.closest('.movieroot').slideUp(200);
				});

				$('.play', _jMovies).live('click', function () {
					_srv.play($(this).m().Files[0]);
				});
				
				$('.edittags', _jMovies).live('click', function () {
					var e = $(this);
					var offset = e.offset();
					var mouseIn;
					var editor = getTemplate('tageditor').css({
                        top: offset.top + e.outerHeight(),
                        left: offset.left
                    }).hover(function(){ 
						mouseIn=true; 
					}, function(){ 
						mouseIn=false; 
					}).appendTo('body');

					var hide = function(){
						if(mouseIn)
							return;
						$("body").unbind('mousedown', hide);
						editor.remove();
					};
					$("body").mousedown(hide);
					
					var m = e.m();
					
					//New tag
					var liAddNew = $('.addnew', editor).keydown(function(e){
						if(e.keyCode == 13){
							_srv.setTag($(this).val(), m.ImdbId);
							editor.remove();
						}
					}).closest('li');
					
					//Remove tag
					$.each(m.Tags, function(i, t){
						$('<a class="remove"/>')
							.text(t)
							.click(function(){
								_srv.setTag(t, m.ImdbId, true);
								editor.remove();
							}).wrap('<li/>').parent().insertBefore(liAddNew);
					});
					
					//Add tag
					$.each(_allTags, function(t){
						if($.inArray(t, m.Tags) >= 0)
							return;
						$('<a class="add"/>')
							.text(t)
							.click(function(){
								_srv.setTag(t, m.ImdbId);
								editor.remove();
							}).wrap('<li/>').parent().insertBefore(liAddNew);
					});
				});
				
				var reload = function(){
					_srv.getData(function (o) {
						setData(o);
					});
				};
				
				$('.btrefresh').click(refresh);
				
				reload();
                
				$('#load').ajaxStart(function() {
					$(this).show();
				}).ajaxStop(function() {
					$(this).hide();
				});
				
				_jSort.change(refresh);
				_jDescending.change(refresh);
				_jTagFilter.change(refresh);
            })
        </script>
    </body>
</html>
